/**
 * 
 */
package IndexComponent;

import java.util.*;

import RecordManagement.RID;

/**
 * @author Neil
 *
 */
public class IX_IndexScan implements IX_IndexScan_Interface {
	
	final public static int OP_EQ = 1;
	final public static int OP_LT = 2;
	final public static int OP_GT = 3;
	final public static int OP_LE = 4;
	final public static int OP_GE = 5;
	
	int compOp;
	Keyword compKey;
	BPlusTree btree;
	boolean closed;
	List<RID> indexBuffer;
	BPlusTreeNode leaf;
	boolean needLoadAgain; //Set in ConstructList(), test in GetNextEntry();
	
	public IX_IndexScan(int compOp, Keyword compKey, BPlusTree btree) {
		this.compOp = compOp;
		this.compKey = compKey;
		this.btree = btree;
		closed = false;
		indexBuffer = new LinkedList<RID>();
		leaf = btree.SearchLeafByKey(compKey);
		ConstructList(leaf);
	}
	
	/* Read the proper rid from the leaf node, and fill them to the list */
	private void ConstructList(BPlusTreeNode btNode) {
		List<Keyword> keyList = btNode.LoadKeyword();
		List<RID> dataList = btNode.LoadData();
		int i;
		switch(compOp) {
		case (OP_EQ):
			for (i=0; i<keyList.size() && keyList.get(i).compareTo(compKey)<0; ++i);
			if (i==keyList.size()) {
				needLoadAgain = false;
				return;
			}
			while (i<keyList.size() && keyList.get(i).compareTo(compKey)==0) 
				indexBuffer.add(dataList.get(i++));
			if (i==btNode.numOfKeyword)
				needLoadAgain = true;
			else
				needLoadAgain = false;
			break;
		case (OP_GT):
			i=keyList.size();
			while (--i>=0 && keyList.get(i).compareTo(compKey)>0)
				indexBuffer.add(0, dataList.get(i));
			needLoadAgain = true;
			break;
		case (OP_GE):
			i=keyList.size();
			while (--i>=0 && keyList.get(i).compareTo(compKey)>=0)
				indexBuffer.add(0, dataList.get(i));
			needLoadAgain = true;
			break;
		case (OP_LT):
			i=-1;
			while (++i<keyList.size() && keyList.get(i).compareTo(compKey)<0)
				indexBuffer.add(0, dataList.get(i));
			needLoadAgain = true;
			break;
		case (OP_LE):
			i=-1;
			while (++i<keyList.size() && keyList.get(i).compareTo(compKey)<=0)
				indexBuffer.add(0, dataList.get(i));
			needLoadAgain = true;
			break;
		}
	}
	
	/* (non-Javadoc)
	 * @see IndexComponent.IX_IndexScan_Interface#CloseScan()
	 */
	@Override
	public void CloseScan() {
		closed = true;
		compKey = null;
		indexBuffer.clear();
		leaf = null;
	}

	/* (non-Javadoc)
	 * @see IndexComponent.IX_IndexScan_Interface#GetNextEntry()
	 */
	@Override
	public RID GetNextEntry() {
		if (closed)
			throw new IX_Abort_Exception("Scan Not Open");
		
		// RID in this block has not used up, suck it.
		if (indexBuffer.size()!=0)
			return indexBuffer.remove(0);

		if (!needLoadAgain)
			return null;
		
		// A neighbor leaf node need loading.
		if (compOp == OP_GE || compOp == OP_GT || compOp == OP_EQ)
			leaf = btree.GetPostLeaf(leaf);
		if (compOp == OP_LE || compOp == OP_LT)
			leaf = btree.GetPreLeaf(leaf);
		
		if (leaf == null) {
			needLoadAgain = false;
			return null;
		}
		
		ConstructList(leaf);
		if (indexBuffer.size()==0) {
			needLoadAgain = false;
			return null;
		}
		return indexBuffer.remove(0);
	}

}
